package com.icesoft.core.dao.criteria;


import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class AndPropertyFilter extends BaseBuilder {

    AndPropertyFilter(FromBuilder fromBuilder) {
        super(fromBuilder);
    }

    List<PropertyFilter.Property> propertys = new ArrayList<>(10);

    AndPropertyFilter copy(FromBuilder fromBuilder) {
        AndPropertyFilter andPropertyFilter = new AndPropertyFilter(fromBuilder);
        andPropertyFilter.propertys.addAll(propertys);
        return andPropertyFilter;
    }

    @Override
    public String toString() {
        return toString(true);
    }

    public String getHql() {
        return toString(false);
    }

    private String toString(boolean isValue) {
        StringBuilder stringBuilder = new StringBuilder();
        boolean isFirst = true;
        for (PropertyFilter.Property filter : propertys) {
            if (!isFirst) {
                stringBuilder.append(" ").append(filter.criteria).append(" ");
            }
            isFirst = false;
            stringBuilder.append(filter.getPropertyName()).append(" ").append(filter.operator.getSymbol()).append(" ");
            QuerySupport support = null;
            if (filter.value instanceof QuerySupport) {
                support = (QuerySupport) filter.value;
            } else if (filter.value instanceof SelectBuilder) {
                SelectBuilder subSelectBuilder = (SelectBuilder) filter.value;
                subSelectBuilder.fromBuilder.subOrder = fromBuilder.subOrder + 1;
                support = new QuerySupport(subSelectBuilder);
            }
            if (support != null) {
                stringBuilder.append('(');
                if (isValue) {
                    stringBuilder.append(support.toString());
                } else {
                    stringBuilder.append(support.getHql());
                }
                stringBuilder.append(')');
                filter.value = support;
            } else if (filter.editOperator || isValue) {
                stringBuilder.append(filter.value);
            } else {
                stringBuilder.append(":").append(filter.getParameterName());

            }
        }
        return stringBuilder.toString();
    }

    /**
     * 子条件
     */
    public PropertyFilter orFilter() {
        return fromBuilder.whereBuilder.orFilter();
    }

    /**
     * 子条件
     */
    public PropertyFilter andFilter() {
        return fromBuilder.whereBuilder.andFilter();
    }

    public AndPropertyFilter filter() {
        return fromBuilder.whereBuilder.filter();
    }

    // and查询
    public AndPropertyFilter andEq(String name, Object value) {
        return and(name, Operator.EQ, value);
    }

    public AndPropertyFilter andGe(String name, Object value) {
        return and(name, Operator.GE, value);
    }

    public AndPropertyFilter andLe(String name, Object value) {
        return and(name, Operator.LE, value);
    }

    public AndPropertyFilter andNe(String name, Object value) {
        return and(name, Operator.NE, value);
    }

    public AndPropertyFilter andGt(String name, Object value) {
        return and(name, Operator.GT, value);
    }

    public AndPropertyFilter andLt(String name, Object value) {
        return and(name, Operator.LT, value);
    }

    public AndPropertyFilter andIn(String name, SelectBuilder selectBuilder) {
        return and(name, Operator.IN, selectBuilder);
    }

    public AndPropertyFilter andNotIn(String name, SelectBuilder selectBuilder) {
        return and(name, Operator.NOT_IN, selectBuilder);
    }

    public AndPropertyFilter andIn(String name, Collection<?> value) {
        if (value == null || value.isEmpty()) {
            return add(Criteria.AND, "1", Operator.EQ, "0", true);
        }
        if (value.size() == 1) {
            return and(name, Operator.EQ, value.iterator().next());
        }
        return and(name, Operator.IN, value);
    }

    public AndPropertyFilter andNotIn(String name, Collection<?> value) {
        if (value == null || value.isEmpty()) {
            return add(Criteria.AND, "1", Operator.EQ, "1", true);
        }
        if (value.size() == 1) {
            return and(name, Operator.NE, value.iterator().next());
        }
        return and(name, Operator.NOT_IN, value);
    }

    public AndPropertyFilter andLike(String name, Object value) {
        return and(name, Operator.LIKE, value);
    }

    public AndPropertyFilter andIsNotNull(String name) {
        return and(name, Operator.IS, "not null");
    }

    public AndPropertyFilter andIsNull(String name) {
        return and(name, Operator.IS, "null");
    }

    AndPropertyFilter and(String name, Operator operator, Object value) {
        return add(Criteria.AND, name, operator, value);
    }

    AndPropertyFilter add(Criteria criteria, String name, Operator operator, Object value) {
        return add(criteria, name, operator, value, false);
    }

    AndPropertyFilter add(Criteria criteria, String name, Operator operator, Object value, boolean editOperator) {
        if (name == null) {
            throw new IllegalArgumentException("查询条件name不能为空");
        }
        if (value == null) {
            throw new IllegalArgumentException("查询条件" + name + "对应的值不能为空");
        }

        this.propertys.add(new Property(criteria, name, operator, value, editOperator, ++fromBuilder.whereBuilder.propertySeq));
        return this;
    }

    public class Property {
        private int order;
        Operator operator;
        /**
         * 原始名
         */
        String name;
        /**
         * 查询属性名
         */
        private String parameterName;
        /**
         * 查询参数名
         */
        private String propertyName;
        private int subOrder;
        Object value;
        boolean editOperator;
        Criteria criteria;

        Property(Criteria criteria, String name, Operator operator, Object value, boolean editOperator, int order) {

            this.editOperator = editOperator;
            this.criteria = criteria;
            this.operator = operator;
            this.name = name;
            this.value = value;
            this.order = order;
            if (operator == Operator.IS) {
                this.editOperator = true;
            }
        }

        public String getPropertyName() {
            if (propertyName == null || fromBuilder.subOrder != subOrder) {
                initPropertyAndParameterName();
            }
            return propertyName;
        }

        public String getParameterName() {
            if (parameterName == null || fromBuilder.subOrder != subOrder) {
                initPropertyAndParameterName();
            }
            return parameterName;
        }


        private void initPropertyAndParameterName() {
            this.propertyName = name;
            if ((!name.contains(".") || !fromBuilder.getTableMap().containsValue(name.split("\\.")[0]))
                    && !StringUtils.isNumeric(name.substring(0, 1))) {
                this.propertyName = fromBuilder.getTableName() + "." + name;
            }
            this.parameterName = this.propertyName.replace(".", "_") + "_" + order;
            if (fromBuilder.subOrder > 0) {
                this.parameterName = parameterName + "_" + fromBuilder.subOrder;
                this.subOrder = fromBuilder.subOrder;
            }
        }

        public Object getValue() {
            return value;
        }

    }
}
